/* Kanvas Paint and Drawing Tool.
 * Copyright (C) 2011 Darryl Wallace
 * wallacdj@gmail.com / darryl@wallynet.ca
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*!
  @file ITool.h
  @author Darryl Wallace
  @date 2011
  @brief This file defines the common interface to all tools.
  */
#ifndef ITOOL_H
#define ITOOL_H

#include <QtGui>
#include "IPlugin.h"

class LayerItem;

/**
  \class ITool
  \brief This class is a base interface class for all tools.

  For tools that are drawing (especially shapes), they should be sub-class QGraphicsItem as well.
  See the code for the RectangleTool and use it as an example.

  \sa RectangleTool
  */
class ITool : public QGraphicsObject, public IPlugin
{
    Q_OBJECT

public:

    /// Defines the type of tool.
    enum ToolType{
        Undefined = -1, /*!< Undefined tool*/
        Drawing = 0,    /*!< Tool used for drawing */
        Eraser = 1,     /*!< Tool used for erasing */
        Selection = 2   /*!< Tool used for selections */
    };

    /// Defines how the canvas should be updated when the tool is drawing
    enum UpdateMode{
        EntireCanvas,   /*<! Update the entire canvas*/
        BoundingRect    /*<! Update only the bounding rect of the tool.*/
    };

    virtual ~ITool() {}

    /// Sets the LayerItem that this tool is operating on.
    virtual void setLayerItem(LayerItem *) = 0;

    PluginType pluginType() const {return Tool;}

    /// Return the tool type.
    virtual ToolType toolType() const = 0;
    /// Sets the primary color for the tool.
    /*!
      This method would be used for drawing tools only.
      */
    virtual void setPrimaryColor(const QColor &) = 0;
    /// Sets the secondary color.
    /*!
      This method would be used for drawing tools only.
      */
    virtual void setSecondaryColor(const QColor &) = 0;

    /// Paint method
    /*!
      This is the expected paint method of a QGraphicsItem.
      This scene should map the path of painting to the scene.
      */
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=0) = 0;

    /// Paint the Tool's result on the image
    /*!
      This will paint the path of the item to the image
      */
    virtual void paintOnImage(QPainter *painter) = 0;

    /// Handle the mouse press event on the scene.
    /*!
      Call e->scenePos() to get the position of the event.
      \param e Mouse event on the scene.
      */
    virtual void handleMousePressEvent(const QGraphicsSceneMouseEvent *e) = 0;

    /// Handle the mouse move event on the scene.
    /*!
      Call e->scenePos() to get the position of the event.
      \param e Mouse event on the scene.
      */
    virtual void handleMouseMoveEvent(const QGraphicsSceneMouseEvent *e) = 0;

    /// Handle the mouse release event on the scene.
    /*!
      Call e->scenePos() to get the position of the event.
      \param e Mouse event on the scene.
      */
    virtual void handleMouseReleaseEvent(const QGraphicsSceneMouseEvent *e) = 0;

    /// Return the bounding rect of where this tool has operated
    /*!
      Depending on the tool, it may be necessary to return the bounding rect
      of where the tool has been working.  It is necessary for invalidating the region
      on the scene required for updating.
      \return The bounding rect.
      */
    virtual QRectF boundingRect() const = 0;

    /// Return the list of widgets to be shown on the toolbar.
    /*!
      Because we want to have custom options for each tool, you must
      create the list of widgets to be displayed on the tool bar.

      The tool bar will parent the items and they should be cleaned up automatically.
      \return List of the widgets that are to be displayed.
      */
    virtual QList<QWidget *> toolbarWidgets() const = 0;

    /// Return the tool cursor.
    /*!
      A tool may require a custom icon for the mouse cursor.
      If you only require the standard cross hair cursor
      then do not reimplement this method.

      \return QCursor for the graphics scene.
      */
    virtual QCursor mouseCursor() const {return QCursor(Qt::CrossCursor);}

    /// Returns the name of this tool
    /*!
      \return name of the tool, I.e. "Paintbrush"
      */
    virtual QString toolName() const = 0;

    /// Returns the mouse tool's icon for the push button
    /*!
      \return QIcon object for the icon
      */
    virtual QIcon toolIcon() const = 0;

    virtual const QPen & pen() const = 0;
    virtual void setPen(const QPen &pen) = 0;

    /// Returns the state of the tool's persistence
    /*!
      A persistent tool is one that maintains selection
      even when the mouse has been released.

      Often, anchors are displayed

      Examples of persistent tool would be the Text or the line tool.
      By default it returns false (e.g. a rectangle tool is not persistent)

      If anchor handles are being used by this tool, ensure to set this function
      to return true otherwise, the canvas will not check for any anchors.

      \return bool - the tool's persistence
      */
    virtual bool isPersistent() const {return false;}

    /// Returns the way the canvas should be updated.
    /*!
      For free-form shapes that may continue to change (e.g. BrushTool's constant adding of
      new points), it is more efficient to update only the bounding rect.  For a shape
      that requires space around it to also be repainted (e.g. A rectangleTool's shrinking
      rectangle) it is necessary to update the Entire canvas.

      The default is to update the entire canvas.

      \return ITool::UpdateMode
      \sa UpdateMode
      */
    virtual UpdateMode updateMode() const {return EntireCanvas;}

    /// Handles the move of an anchor
    /*!
      When an anchor moves it should call this on it's parent.

      \param anchor The anchor that is calling the event.  It is up to ITool to function properly based on the Anchor that is selected.
      \param event The event that the anchor has experienced.
      */
    virtual void handleAnchorMove(QGraphicsItem *anchor, QGraphicsSceneEvent *event) {Q_UNUSED(anchor); Q_UNUSED(event);}

    /// Returns the list of anchor handles.
    /*!
      Anchor handles should all be created by this tool on construction.
      The canvas will take care of showing them (on mouseReleaseEvent).  If the tool does not
      receive any more events, the anchor handles will not be shown (setVisible(false)) and
      the anchor will not receive any more events.

      \return QList of QGraphicsItems that are anchors.
      */
    virtual QList<QGraphicsItem * /*anchorHandles */> anchorHandles() const {return QList<QGraphicsItem *>();}

signals:
    void statusMessage(const QString &);

};

#endif // ITOOL_H
